<!doctype html>
<html lang="en">
    <head>
        <title>{#SETTINGS}</title>
        {#HTML_HEADER}
    </head>
    <body>
        {#HTML_NAV}
        <div id="wrapper">
            <div id="content">
                <form method="post" action="/save" id="settings">
                    <button type="button" class="s_collapsible mt-4">{#SYSTEM_CONFIG}</button>
                    <div class="s_content">
                        <fieldset class="mb-2">
                            <legend class="des">{#SYSTEM_CONFIG}</legend>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3">{#DEVICE_NAME}</div>
                                <div class="col-12 col-sm-9"><input type="text" name="device"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-8 col-sm-3">{#REBOOT_AT_MIDNIGHT}</div>
                                <div class="col-4 col-sm-9"><input type="checkbox" name="schedReboot"/></div>
                            </div>
                            <div class="row mb-5">
                                <div class="col-8 col-sm-3">{#DARK_MODE}</div>
                                <div class="col-4 col-sm-9"><input type="checkbox" name="darkMode"/></div>
                                <div class="col-12">{#DARK_MODE_NOTE}</div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-8 col-sm-3">{#REGION}</div>
                                <div class="col-4 col-sm-9" id="region"></div>
                            </div>
                            <div class="row mb-5">
                                <div class="col-8 col-sm-3">{#TIMEZONE}</div>
                                <div class="col-4 col-sm-9" id="timezone"></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-8 col-sm-3">{#CUSTOM_LINK}</div>
                                <div class="col-4 col-sm-9"><input type="text" name="cstLnk"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-8 col-sm-3">{#CUSTOM_LINK_TEXT}</div>
                                <div class="col-4 col-sm-9"><input type="text" name="cstLnkTxt"/></div>
                            </div>
                        </fieldset>
                        <fieldset class="mb-4" id="serialCb">
                            <legend class="des">{#SERIAL_CONSOLE}</legend>
                        </fieldset>
                    </div>

                    <button type="button" class="s_collapsible">{#NETWORK}</button>
                    <div class="s_content">
                        <fieldset class="mb-2">
                            <legend class="des">WiFi</legend>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#AP_PWD}</div>
                                <div class="col-12 col-sm-9"><input type="text" name="ap_pwd" minlength="8" /></div>
                            </div>
                            <div class="row mb-2 mb-sm-3">
                                <div class="col-12 col-sm-3 my-2">SSID</div>
                                <div class="col-12 col-sm-9">
                                    <input type="text" name="ssid"/><br/>
                                    <a href="/wizard">{#SCAN_WIFI}</a>
                                </div>
                            </div>
                            <div class="row mb-2 mb-sm-3">
                                <div class="col-12 col-sm-3">{#SSID_HIDDEN}</div>
                                <div class="col-12 col-sm-9"><input type="checkbox" name="hidd"/></div>
                            </div>
                            <div class="row mb-2 mb-sm-3">
                                <div class="col-12 col-sm-3 my-2">{#PASSWORD}</div>
                                <div class="col-12 col-sm-9"><input type="password" name="pwd" value="{PWD}"/></div>
                            </div>
                        </fieldset>
                        <fieldset class="mb-4">
                            <legend class="des">{#STATIC_IP}</legend>
                            <p>
                                {#NETWORK_HINT_BLANK}
                            </p>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#IP_ADDRESS}</div>
                                <div class="col-12 col-sm-9"><input type="text" name="ipAddr" maxlength="15" /></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#SUBMASK}</div>
                                <div class="col-12 col-sm-9"><input type="text" name="ipMask" maxlength="15" /></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">DNS 1</div>
                                <div class="col-12 col-sm-9"><input type="text" name="ipDns1" maxlength="15" /></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">DNS 2</div>
                                <div class="col-12 col-sm-9"><input type="text" name="ipDns2" maxlength="15" /></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">Gateway</div>
                                <div class="col-12 col-sm-9"><input type="text" name="ipGateway" maxlength="15" /></div>
                            </div>
                        </fieldset>
                    </div>

                    <button type="button" class="s_collapsible">{#PROTECTION}</button>
                    <div class="s_content">
                        <fieldset class="mb-4">
                            <legend class="des mx-2">{#PROTECTION}</legend>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 mb-2 mt-2">{#ADMIN_PASSWORD}</div>
                                <div class="col-12 col-sm-9"><input type="password" name="adminpwd" value="{PWD}"/></div>
                            </div>
                            <p>{#PROTECTION_NOTE}</p>
                            <div id="prot_mask"></div>
                        </fieldset>
                    </div>

                    <button type="button" class="s_collapsible">{#INVERTER}</button>
                    <div class="s_content">
                        <fieldset class="mb-4">
                        <legend class="des">{#INVERTER}</legend>
                            <div id="inverter"></div>
                            <div class="row mb-3">
                                <div class="col-8 my-2">{#INTERVAL} [s]</div>
                                <div class="col-4"><input type="number" name="invInterval" title="Invalid input"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-8 mb-2">{#INV_RESET_MIDNIGHT}</div>
                                <div class="col-4"><input type="checkbox" name="invRstMid"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-8 mb-2">{#INV_RESET_SUNRISE}</div>
                                <div class="col-4"><input type="checkbox" name="invRstComStart"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-8 mb-2">{#INV_RESET_SUNSET}</div>
                                <div class="col-4"><input type="checkbox" name="invRstComStop"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-8">{#INV_RESET_NOT_AVAIL}</div>
                                <div class="col-4"><input type="checkbox" name="invRstNotAvail"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-8">{#INV_RESET_MAX_VALUES}</div>
                                <div class="col-4"><input type="checkbox" name="invRstMaxMid"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-8">{#INV_START_WITHOUT_TIME}</div>
                                <div class="col-4"><input type="checkbox" name="strtWthtTm"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-8">{#INV_READ_GRID_PROFILE}</div>
                                <div class="col-4"><input type="checkbox" name="rdGrid"/></div>
                            </div>
                        </fieldset>
                    </div>

                    <button type="button" class="s_collapsible">NTP Server</button>
                    <div class="s_content">
                        <fieldset class="mb-4">
                            <legend class="des">NTP Server</legend>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">NTP Server / IP</div>
                                <div class="col-12 col-sm-9"><input type="text" name="ntpAddr"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">NTP Port</div>
                                <div class="col-12 col-sm-9"><input type="number" name="ntpPort"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#NTP_INTERVAL}</div>
                                <div class="col-12 col-sm-9"><input type="number" name="ntpIntvl"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#NTP_SET_SYS_TIME}</div>
                                <div class="col-12 col-sm-9">
                                    <input type="button" name="ntpBtn" id="ntpBtn" class="btn" value="{#BTN_FROM_BROWSER}" onclick="setTime()"/>
                                    <input type="button" name="ntpSync" id="ntpSync" class="btn" value="{#BTN_SYNC_NTP}" onclick="syncTime()"/><br/>
                                    <span id="apiResultNtp"></span>
                                </div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#NTP_SYS_TIME}</div>
                                <div class="col-12 col-sm-9 my-2"><span id="date"></span></div>
                            </div>
                        </fieldset>
                    </div>

                    <button type="button" class="s_collapsible">{#SUNRISE_SUNSET}</button>
                    <div class="s_content">
                        <fieldset class="mb-4">
                            <legend class="des">{#SUNRISE_SUNSET}</legend>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#LATITUDE}</div>
                                <div class="col-12 col-sm-9"><input type="number" name="sunLat" step="any"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#LONGITUDE}</div>
                                <div class="col-12 col-sm-9"><input type="number" name="sunLon" step="any"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#OFFSET_SUNRISE}</div>
                                <div class="col-12 col-sm-9"><select name="sunOffsSr"></select></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#OFFSET_SUNSET}</div>
                                <div class="col-12 col-sm-9"><select name="sunOffsSs"></select></div>
                            </div>
                        </fieldset>
                    </div>

                    <button type="button" class="s_collapsible">MQTT</button>
                    <div class="s_content">
                        <fieldset class="mb-4">
                            <legend class="des">MQTT</legend>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">Broker / Server IP</div>
                                <div class="col-12 col-sm-9"><input type="text" name="mqttAddr"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">Port</div>
                                <div class="col-12 col-sm-9"><input type="number" name="mqttPort"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">Client Id (optional)</div>
                                <div class="col-12 col-sm-9"><input type="text" name="mqttClientId"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#MQTT_USER}</div>
                                <div class="col-12 col-sm-9"><input type="text" name="mqttUser"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#MQTT_PASSWORD}</div>
                                <div class="col-12 col-sm-9"><input type="password" name="mqttPwd"/></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">Topic</div>
                                <div class="col-12 col-sm-9"><input type="text" name="mqttTopic" pattern="[\-\+A-Za-z0-9\.\/#\$%&=_]+" title="Invalid input" /></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#MQTT_JSON}</div>
                                <div class="col-12 col-sm-9"><input type="checkbox" name="mqttJson" /></div>
                            </div>
                            <p class="des">{#MQTT_NOTE}</p>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">{#INTERVAL}</div>
                                <div class="col-12 col-sm-9"><input type="number" name="mqttInterval" title="Invalid input" /></div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-12 col-sm-3 my-2">Discovery Config (homeassistant)</div>
                                <div class="col-12 col-sm-9">
                                    <input type="button" name="mqttDiscovery" id="mqttDiscovery" class="btn" value="{#BTN_SEND}" onclick="sendDiscoveryConfig()"/>
                                    <span id="apiResultMqtt"></span>
                                </div>
                            </div>
                            <div class="row mb-3">
                                <div class="col-8 col-sm-3">{#RETAIN}</div>
                                <div class="col-4 col-sm-9"><input type="checkbox" name="retain"/></div>
                            </div>
                        </fieldset>
                    </div>

                    <button type="button" class="s_collapsible">{#PINOUT_CONFIG}</button>
                    <div class="s_content">
                        <fieldset class="mb-4">
                            <legend class="des">{#PINOUT_CONFIG}</legend>
                            <p class="des">Status LEDs</p>
                            <div id="pinout"></div>

                            <p class="des">{#RADIO} (NRF24L01+)</p>
                            <div id="rf24"></div>
                            <!--IF_ESP32-->
                            <p class="des">{#RADIO} (CMT2300A)</p>
                            <div id="cmt"></div>
                            <!--ENDIF_ESP32-->
                            <!--IF_ETHERNET-->
                            <p class="des">Ethernet</p>
                            <div id="eth"></div>
                            <!--ENDIF_ETHERNET-->
                        </fieldset>
                    </div>
                    <!--IF_PLUGIN_DISPLAY-->
                    <button type="button" class="s_collapsible">{#DISPLAY_CONFIG}</button>
                    <div class="s_content">
                        <fieldset class="mb-4">
                            <legend class="des">{#DISPLAY_CONFIG}</legend>
                            <div id="dispType"></div>
                            <div id="dispRot"></div>
                            <div class="row mb-3">
                                <div class="col-8 col-sm-3">{#DISP_OFF_INV}</div>
                                <div class="col-4 col-sm-9"><input type="checkbox" name="disp_pwr"/></div>
                            </div>
                            <div id="screenSaver"></div>
                            <div class="row mb-3" id="luminanceOption">
                                <div class="col-12 col-sm-3 my-2">{#DISP_LUMINANCE}</div>
                                <div class="col-12 col-sm-9"><input type="number" name="disp_cont" min="0" max="255"></div>
                            </div>
                            <p class="des">{#DISP_PINOUT}</p>
                            <div id="dispPins"></div>
                            <div id="pirPin"></div>
                            <div id="graphOptions">
                                <p class="des">{#GRAPH_OPTIONS}</p>
                                <div class="row mb-3">
                                    <div class="col-12 col-sm-3 my-2">{#GRAPH_SHOW_RATIO}</div>
                                    <div class="col-12 col-sm-9"><input type="number" name="disp_graph_ratio" min="0" max="100"></div>
                                </div>
                                <div id="graphSize"></div>
                            </div>
                        </fieldset>
                    </div>
                    <!--ENDIF_PLUGIN_DISPLAY-->

                    <div class="row mb-4 mt-4">
                        <div class="col-8 col-sm-3">{#BTN_REBOOT_SUCCESSFUL_SAVE}</div>
                        <div class="col-4 col-sm-9">
                            <input type="checkbox" name="reboot" checked />
                            <input type="submit" value="{#BTN_SAVE}" class="btn right"/>
                        </div>
                    </div>
                </form>
                <div class="hr mb-3 mt-3"></div>
                <div class="mb-4 mt-4">
                    <a class="btn" href="/erase">{#BTN_ERASE}</a>
                    <fieldset class="mb-4">
                        <legend class="des">{#IM_EXPORT}</legend>
                        <div class="row mb-4 mt-4">
                            <div class="col-12 col-sm-3">{#IMPORT}</div>
                            <div class="col-12 col-sm-9">
                                <form id="form" method="POST" action="/upload" enctype="multipart/form-data" accept-charset="utf-8">
                                    <div class="row">
                                        <div class="col-12 col-sm-8 my-2"><input type="file" id="importFileInput" name="upload"></div>
                                        <div class="col-12 col-sm-4 my-2"><input type="button" id="importButton" class="btn" value="Import" onclick="hide()"></div>
                                    </div>
                                </form>
                            </div>
                        </div>
                        <div class="row mb-4 mt-4">
                            <div class="col-12 col-sm-3 my-2">{#EXPORT}</div>
                            <div class="col-12 col-sm-9">
                                <a class="btn" href="/get_setup" target="_blank">{#BTN_EXPORT}</a><span> {#EXPORT_NOTE}</span>
                            </div>
                        </div>
                    </fieldset>
                </div>
            </div>
        </div>
        {#HTML_FOOTER}
        <script type="text/javascript">
            var maxInv = 0;
            var ts = 0;

            /*IF_ESP8266*/
            var esp8266pins = [
                [255, "{#PIN_OFF}"],
                [0, "D3 (GPIO0)"],
                [1, "TX (GPIO1)"],
                [2, "D4 (GPIO2)"],
                [3, "RX (GPIO3)"],
                [4, "D2 (GPIO4, SDA)"],
                [5, "D1 (GPIO5, SCL)"],
                [6, "GPIO6"],
                [7, "GPIO7"],
                [8, "GPIO8"],
                [9, "GPIO9"],
                [10, "GPIO10"],
                [11, "GPIO11"],
                [12, "D6 (GPIO12)"],
                [13, "D7 (GPIO13)"],
                [14, "D5 (GPIO14)"],
                [15, "D8 (GPIO15)"],
                [16, "D0 (GPIO16 - {#PIN_NO_IRQ})"]
            ];
            /*ENDIF_ESP8266*/

            /*IF_ESP32*/
            var esp32pins = [
                [255, "{#PIN_OFF}"],
                [0,  "GPIO0"],
                [1,  "TX (GPIO1)"],
                [2,  "GPIO2 (LED)"],
                [3,  "RX (GPIO3)"],
                [4,  "GPIO4"],
                [5,  "GPIO5"],
                [12, "GPIO12 (HSPI MISO)"],
                [13, "GPIO13 (HSPI MOSI)"],
                [14, "GPIO14 (HSPI SCLK)"],
                [15, "GPIO15"],
                [16, "GPIO16"],
                [17, "GPIO17"],
                [18, "GPIO18 (VSPI SCLK)"],
                [19, "GPIO19 (VSPI MISO)"],
                [21, "GPIO21 (SDA)"],
                [22, "GPIO22 (SCL)"],
                [23, "GPIO23 (VSPI MOSI)"],
                [25, "GPIO25"],
                [26, "GPIO26"],
                [27, "GPIO27"],
                [32, "GPIO32"],
                [33, "GPIO33"],
                [34, "GPIO34 ({#PIN_INPUT_ONLY})"],
                [35, "GPIO35 ({#PIN_INPUT_ONLY})"],
                [36, "VP (GPIO36, {#PIN_INPUT_ONLY})"],
                [39, "VN (GPIO39, {#PIN_INPUT_ONLY})"]
            ];
            /*IF_ESP32-S2*/
            var esp32sXpins = [
                [255, "off / default"],
                [0,  "GPIO0 ({#PIN_DONT_USE} - BOOT)"],
                [1,  "GPIO1"],
                [2,  "GPIO2"],
                [3,  "GPIO3"],
                [4,  "GPIO4"],
                [5,  "GPIO5"],
                [6,  "GPIO6"],
                [7,  "GPIO7"],
                [8,  "GPIO8"],
                [9,  "GPIO9"],
                [10, "GPIO10"],
                [11, "GPIO11"],
                [12, "GPIO12"],
                [13, "GPIO13"],
                [14, "GPIO14"],
                [15, "GPIO15"],
                [16, "GPIO16"],
                [17, "GPIO17"],
                [18, "GPIO18"],
                [19, "GPIO19 ({#PIN_DONT_USE} - USB-)"],
                [20, "GPIO20 ({#PIN_DONT_USE} - USB+)"],
                [21, "GPIO21"],
                [26, "GPIO26 (PSRAM - {#PIN_NOT_AVAIL})"],
                [27, "GPIO27 (FLASH - {#PIN_NOT_AVAIL})"],
                [28, "GPIO28 (FLASH - {#PIN_NOT_AVAIL})"],
                [29, "GPIO29 (FLASH - {#PIN_NOT_AVAIL})"],
                [30, "GPIO30 (FLASH - {#PIN_NOT_AVAIL})"],
                [31, "GPIO31 (FLASH - {#PIN_NOT_AVAIL})"],
                [32, "GPIO32 (FLASH - {#PIN_NOT_AVAIL})"],
                [33, "GPIO33 (not exposed on S3-WROOM modules)"],
                [34, "GPIO34 (not exposed on S3-WROOM modules)"],
                [35, "GPIO35"],
                [36, "GPIO36"],
                [37, "GPIO37"],
                [38, "GPIO38"],
                [39, "GPIO39"],
                [40, "GPIO40"],
                [41, "GPIO41"],
                [42, "GPIO42"],
                [43, "GPIO43"],
                [44, "GPIO44"],
                [45, "GPIO45 ({#PIN_DONT_USE} - STRAPPING PIN)"],
                [46, "GPIO46 ({#PIN_DONT_USE} - STRAPPING PIN)"],
                [47, "GPIO47"],
                [48, "GPIO48"],
            ];
            /*ENDIF_ESP32-S2*/
            /*IF_ESP32-S3*/
            var esp32sXpins = [
                [255, "off / default"],
                [0,  "GPIO0 ({#PIN_DONT_USE} - BOOT)"],
                [1,  "GPIO1"],
                [2,  "GPIO2"],
                [3,  "GPIO3"],
                [4,  "GPIO4 (CMT CSB)"],
                [5,  "GPIO5 (CMT SDIO)"],
                [6,  "GPIO6 (CMT SCLK)"],
                [7,  "GPIO7"],
                [8,  "GPIO8 (CMT GPIO3)"],
                [9,  "GPIO9 (DATA display)"],
                [10, "GPIO10 (SCK display)"],
                [11, "GPIO11 (CS display)"],
                [12, "GPIO12 (DC display)"],
                [13, "GPIO13 (RST display)"],
                [14, "GPIO14 (BUSY display)"],
                [15, "GPIO15"],
                [16, "GPIO16"],
                [17, "GPIO17"],
                [18, "GPIO18"],
                [19, "GPIO19 ({#PIN_DONT_USE} - USB-)"],
                [20, "GPIO20 ({#PIN_DONT_USE} - USB+)"],
                [21, "GPIO21 (CMT FCSB)"],
                [26, "GPIO26 (PSRAM - {#PIN_NOT_AVAIL})"],
                [27, "GPIO27 (FLASH - {#PIN_NOT_AVAIL})"],
                [28, "GPIO28 (FLASH - {#PIN_NOT_AVAIL})"],
                [29, "GPIO29 (FLASH - {#PIN_NOT_AVAIL})"],
                [30, "GPIO30 (FLASH - {#PIN_NOT_AVAIL})"],
                [31, "GPIO31 (FLASH - {#PIN_NOT_AVAIL})"],
                [32, "GPIO32 (FLASH - {#PIN_NOT_AVAIL})"],
                [33, "GPIO33 (not exposed on S3-WROOM modules)"],
                [34, "GPIO34 (not exposed on S3-WROOM modules)"],
                [35, "GPIO35 (MOSI NRF24)"],
                [36, "GPIO36 (SCK NRF24)"],
                [37, "GPIO37 (CSN NRF24)"],
                [38, "GPIO38 (CE NRF24)"],
                [39, "GPIO39 (SCK ETH)"],
                [40, "GPIO40 (MOSI ETH)"],
                [41, "GPIO41 (MISO ETH)"],
                [42, "GPIO42 (CS ETH)"],
                [43, "GPIO43 (RST ETH)"],
                [44, "GPIO44 (INT ETH)"],
                [45, "GPIO45 ({#PIN_DONT_USE} - STRAPPING PIN)"],
                [46, "GPIO46 ({#PIN_DONT_USE} - STRAPPING PIN)"],
                [47, "GPIO47 (IRQ NRF24)"],
                [48, "GPIO48 (MISO NRF24)"],
            ];
            /*ENDIF_ESP32-S3*/
            /*IF_ESP32-C3*/
            var esp32c3pins = [
                [255, "off / default"],
                [0,  "GPIO0"],
                [1,  "GPIO1"],
                [2,  "GPIO2"],
                [3,  "GPIO3"],
                [4,  "GPIO4"],
                [5,  "GPIO5"],
                [6,  "GPIO6"],
                [7,  "GPIO7"],
                [8,  "GPIO8"],
                [9,  "GPIO9"],
                [10, "GPIO10"],
                [11, "GPIO11"],
                [12, "GPIO12 (PSRAM/FLASH)"],
                [13, "GPIO13 (PSRAM/FLASH)"],
                [14, "GPIO14 (PSRAM/FLASH)"],
                [15, "GPIO15 (PSRAM/FLASH)"],
                [16, "GPIO16 (PSRAM/FLASH)"],
                [17, "GPIO17 (PSRAM/FLASH)"],
                [18, "GPIO18 ({#PIN_DONT_USE} - USB-)"],
                [19, "GPIO19 ({#PIN_DONT_USE} - USB+)"],
                [20, "GPIO20 (RX)"],
                [21, "GPIO21 (TX)"],
            ];
            /*ENDIF_ESP32-C3*/
            /*ENDIF_ESP32*/
            var nrfPa = [
                [0, "MIN ({#PIN_RECOMMENDED})"],
                [1, "LOW"],
                [2, "HIGH"],
                [3, "MAX ({#PIN_EXPERIMENTAL})"]
            ];
            var esp32cmtPa = [];
            var esp32cmtFreq = [];

            /*IF_ESP32*/
            var freqFmt = new Intl.NumberFormat('en-US', {
                minimumIntegerDigits: 3,
                minimumFractionDigits: 2
            });
            for(var i = 0; i < 31; i++) {
                esp32cmtPa.push([i, String(i-10) + " dBm"]);
            }
            /*ENDIF_ESP32*/
            var led_high_active = [
                [0, "{#PIN_LOW_ACTIVE}"],
                [1, "{#PIN_HIGH_ACTIVE}"],
            ];

            window.onload = function() {
                for(it of document.getElementsByClassName("s_collapsible")) {
                    it.addEventListener("click", function() {
                        this.classList.toggle("active");
                        var content = this.nextElementSibling;
                        content.style.display = (content.style.display === "block") ? "none" : "block";
                    });
                }

                document.getElementById("settings").addEventListener("submit", function() {
                    var inputs = document.querySelectorAll("input[type='number']");
                    for (var i = 0; i < inputs.length; i++) {
                        if (inputs[i].value.indexOf(",") != -1)
                            inputs[i].value = inputs[i].value.replace(",", ".");
                    }
                });
            }

            function apiCbWifi(obj) {
                var e = document.getElementById("networks");
                selDelAllOpt(e);
                if(obj["success"])
                    e.appendChild(opt("-1", "{#NETWORK_SCANNING}"))
                else
                    e.appendChild(opt("-1", "{#ERROR} " + obj["error"]));
            }

            function apiCbNtp(obj) {
                var e = document.getElementById("apiResultNtp");
                if(obj["success"])
                    e.innerHTML = "{#NTP_COMMAND_EXE}";
                else
                    e.innerHTML = "{#ERROR} " + obj["error"];
            }

            function apiCbNtp2(obj) {
                var e = document.getElementById("apiResultNtp");
                var date = new Date(obj["ts_now"] * 1000);
                e.innerHTML = "{#NTP_SYNCED_AT}: " + toIsoDateStr(date) + ", {#NTP_DIFF}: " + (ts - obj["ts_now"]) + "ms";
            }

            function apiCbMqtt(obj) {
                var e = document.getElementById("apiResultMqtt");
                if(obj["success"])
                    e.innerHTML = "{#MQTT_EXE}";
                else
                    e.innerHTML = "{#ERROR} " + obj["error"];
            }

            function setTime() {
                var date = new Date()
                var obj = {cmd: "set_time", token: "*", val: parseInt(date.getTime() / 1000)}
                getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj))
                setTimeout(function() {getAjax('/api/index', apiCbNtp2)}, 2000)
            }

            function syncTime() {
                var obj = {cmd: "sync_ntp", token: "*"}
                getAjax("/api/setup", apiCbNtp, "POST", JSON.stringify(obj))
                setTimeout(function() {getAjax('/api/index', apiCbNtp2)}, 2000)
            }

            function sendDiscoveryConfig() {
                var obj = {cmd: "discovery_cfg", token: "*"}
                getAjax("/api/setup", apiCbMqtt, "POST", JSON.stringify(obj));
            }

            document.addEventListener('DOMContentLoaded', () => {
                const fileInput = document.querySelector('#importFileInput');
                const button = document.querySelector('#importButton');
                button.disabled = true;
                button.title = "Please select a file first";
                fileInput.addEventListener('change', () => {
                    if (fileInput.value) {
                        button.disabled = false;
                        button.title = "";
                    } else {
                        button.disabled = true;
                        button.title = "Please select a file first";
                    }
                });
            });

            function hide() {
                document.getElementById("form").submit();
                var e = document.getElementById("content");
                e.replaceChildren(span("{#IMPORT_UPLOAD_STARTED}"));
            }

            function delIv() {
                var id = this.id.substring(0, this.id.length-3);
                document.getElementById(id).remove();
            }

            function mlCb(id, des, chk=false) {
                var cb = ml("input", {type: "checkbox", id: id, name: id}, "");
                if(chk)
                    cb.checked = true;
                return ml("div", {class: "row mb-3"}, [
                    ml("div", {class: "col-8 col-sm-3"}, des),
                    ml("div", {class: "col-4 col-sm-9"}, cb)
                ]);
            }

            function mlE(des, e) {
                return ml("div", {class: "row mb-3"}, [
                    ml("div", {class: "col-12 col-sm-3 my-2"}, des),
                    ml("div", {class: "col-12 col-sm-9"}, e)
                ]);
            }

            function getFreeId() {
                var id = 0;
                while(id < maxInv) {
                    if(null == document.getElementById("inv" + id))
                        return id;
                    id++;
                }
                return null;
            }

            function ivGlob(obj) {
                for(var i of [["invInterval", "interval"]])
                    document.getElementsByName(i[0])[0].value = obj[i[1]];
                for(var i of ["Mid", "ComStop", "ComStart", "NotAvail", "MaxMid"])
                    document.getElementsByName("invRst"+i)[0].checked = obj["rst" + i];
                document.getElementsByName("strtWthtTm")[0].checked = obj["strtWthtTm"];
                document.getElementsByName("rdGrid")[0].checked = obj["rdGrid"];
            }

            function parseSys(obj) {
                document.getElementsByName("device")[0].value = obj.device_name;
                for(var i of [["ssid", "ssid"], ["ap_pwd", "ap_pwd"]])
                    document.getElementsByName(i[0])[0].value = obj.network[i[1]];
                document.getElementsByName("hidd")[0].checked = obj.network.hidd;

                document.getElementsByName("darkMode")[0].checked = obj.dark_mode;
                document.getElementsByName("schedReboot")[0].checked = obj.sched_reboot;
                e = document.getElementsByName("adminpwd")[0];
                if(!obj.pwd_set)
                    e.value = "";
                var d = document.getElementById("prot_mask");
                var a = ["Index", "{#NAV_LIVE}", "{#NAV_WEBSERIAL}", "{#NAV_SETTINGS}", "Update", "System", "{#NAV_HISTORY}"];
                var el = [];
                for(var i = 0; i < 7; i++) {
                    var chk = ((obj.prot_mask & (1 << i)) == (1 << i));
                    el.push(mlCb("protMask" + i, a[i], chk))
                }
                d.append(...el);
            }

            function parseGeneric(obj) {
                parseNav(obj)
                parseESP(obj)
                parseRssi(obj)
                parseTitle(obj)

                if(0 != obj.cst_lnk.length) {
                    document.getElementsByName("cstLnk")[0].value = obj.cst_lnk
                    document.getElementsByName("cstLnkTxt")[0].value = obj.cst_lnk_txt
                }

                ts = obj.ts_now;
                window.setInterval("tick()", 1000);

                var tz = []
                for(i = 0; i < 24; i += 0.5)
                    tz.push([i, ((i-12 > 0) ? "+" : "") + String(i-12)]);
                document.getElementById("timezone").append(sel("timezone", tz, obj.timezone + 12))
                var region = [[0, "Europe (860 - 870 MHz)"], [1, "USA, Indonesia (905 - 925 MHz)"], [2, "Brazil (915 - 928 MHz)"]]
                document.getElementById("region").append(sel("region", region, obj.region))
            }

            function parseStaticIp(obj) {
                for(var i of [["ipAddr", "ip"], ["ipMask", "mask"], ["ipDns1", "dns1"], ["ipDns2", "dns2"], ["ipGateway", "gateway"]])
                    if(null != obj[i[1]])
                        document.getElementsByName(i[0])[0].value = obj[i[1]];
            }

            function parseIv(obj) {
                maxInv = obj["max_num_inverters"];
                var lines = [];
                lines.push(ml("tr", {}, [
                    ml("th", {style: "width: 10%; text-align: center;"}, ""),
                    ml("th", {}, "Name"),
                    ml("th", {class: "d-none d-sm-cell"}, "Serial"),
                    ml("th", {style: "width: 10%; text-align: center;"}, "{#INV_EDIT}"),
                    ml("th", {style: "width: 10%; text-align: center;"}, "{#INV_DELETE}")
                ]));

                for(let i = 0; i < obj.inverter.length; i++) {
                    lines.push(ml("tr", {}, [
                        ml("td", {}, badge(obj.inverter[i].enabled, (obj.inverter[i].enabled) ? "{#ENABLED}" : "{#DISABLED}")),
                        ml("td", {}, obj.inverter[i].name),
                        ml("td", {class: "d-none d-sm-cell"}, String(obj.inverter[i].serial)),
                        ml("td", {style: "text-align: center;", onclick: function() {ivModal(obj.inverter[i]);}}, svg(iconGear, 25, 25, "icon icon-fg pointer")),
                        ml("td", {style: "text-align: center; ", onclick: function() {ivDel(obj.inverter[i]);}}, svg(iconDel, 25, 25, "icon icon-fg pointer"))
                    ]));
                }

                var add = new Object();
                add.id = obj.inverter.length;
                add.name = "";
                add.enabled = true;
                add.ch_max_pwr = [400,400,400,400,400,400];
                add.ch_name = [];
                add.ch_yield_cor = [];
                add.freq = 12;
                add.pa = 30;

                var e = document.getElementById("inverter");
                e.innerHTML = ""; // remove all childs
                e.append(ml("table", {class: "table"}, ml("tbody", {}, lines)));
                if(obj.max_num_inverters > obj.inverter.length)
                    e.append(ml("div", {class: "row my-3"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", value: "{#BTN_INV_ADD}", class: "btn", onclick: function() { ivModal(add); }}, null))));

                ivGlob(obj);
            }

            function divRow(item0, item1) {
                return ml("div", {class: "row mb-3"}, [
                    ml("div", {class: "col-3 mt-2"}, item0),
                    ml("div", {class: "col-9"}, item1)
                ])
            }

            function ivModal(obj) {
                var lines = [];
                lines.push(ml("tr", {}, [
                    ml("th", {style: "width: 10%;"}, "{#INV_INPUT}"),
                    ml("th", {}, "{#INV_MAX_MODULE_POWER} [Wp]"),
                    ml("th", {}, "Name (optional)"),
                    ml("th", {}, "{#INV_YIELD_CORR} [kWh] (optional)")
                ]));

                for(let i = 0; i < 6; i++) {
                    lines.push(ml("tr", {id: "ch"+i}, [
                        ml("td", {}, String(i+1)),
                        ml("td", {}, ml("input", {name: "ch_p"+i, class: "text", type: "number", max: 999, value: obj.ch_max_pwr[i]}, null)),
                        ml("td", {}, ml("input", {name: "ch_n"+i, class: "text", type: "text", maxlength: 15, value: (undefined === obj.ch_name[i]) ? "" : obj.ch_name[i]}, null)),
                        ml("td", {}, ml("input", {name: "yld_c"+i, class: "text", type: "number", max: 999999, value: obj.ch_yield_cor[i], step: "0.001"}, null))
                    ]));
                }

                var cbEn = ml("input", {name: "enable", type: "checkbox"}, null);
                var cbDisNightCom = ml("input", {name: "disnightcom", type: "checkbox"}, null);
                cbEn.checked = (obj.enabled);
                cbDisNightCom.checked = (obj.disnightcom);

                var ser = ml("input", {name: "ser", class: "text", type: "text", pattern: "[0-9a-fA-F]{12}", value: obj.serial}, null);
                var html = ml("div", {}, [
                    tabs(["{#TAB_GENERAL}", "{#TAB_INPUTS}", "{#TAB_RADIO}", "{#TAB_ADVANCED}"]),
                    ml("div", {id: "div{#TAB_GENERAL}", class: "tab-content"}, [
                        divRow("{#INV_ENABLE}", cbEn),
                        divRow("{#INV_SERIAL}", ser),
                        divRow("Name", ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null))
                    ]),
                    ml("div", {id: "div{#TAB_INPUTS}", class: "tab-content hide"}, [
                        ml("div", {class: "row mb-3"},
                            ml("table", {class: "table"}, ml("tbody", {}, lines))
                        )
                    ]),
                    ml("div", {id: "div{#TAB_RADIO}", class: "tab-content hide"}, [
                        ml("input", {type: "hidden", name: "isnrf"}, null),
                        ml("div", {id: "setcmt"}, [
                            divRow("{#INV_FREQUENCY}", sel("freq", esp32cmtFreq, obj.freq)),
                            divRow("{#INV_POWER_LEVEL}", sel("cmtpa", esp32cmtPa, obj.pa)),
                            divRow("{#INV_SEARCH}", ml("input", {type: "button", value: "{#BTN_SEARCH}", class: "btn", onclick: function() { cmtSearch(); }}, null))
                        ]),
                        ml("div", {id: "setnrf"},
                            divRow("{#INV_POWER_LEVEL}", sel("nrfpa", nrfPa, obj.pa))
                        ),
                    ]),
                    ml("div", {id: "div{#TAB_ADVANCED}", class: "tab-content hide"}, [
                        ml("div", {class: "row mb-3"}, [
                            ml("div", {class: "col-10"}, "{#INV_PAUSE_DURING_NIGHT}"),
                            ml("div", {class: "col-2"}, cbDisNightCom)
                        ])
                    ]),
                    ml("div", {class: "row mt-5"}, [
                        ml("div", {class: "col-8", id: "res"}, ""),
                        ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "{#BTN_SAVE}", class: "btn", onclick: function() { ivSave(); }}, null))
                    ])
                ]);

                ['keyup', 'change'].forEach(function(evt) {
                    ser.addEventListener(evt, (e) => {
                        var sn = parseInt(ser.value, 16);
                        sn = Math.floor(sn / Math.pow(2, 32));

                        var max = 1;
                        switch(sn & 0x00f0) {
                            case 0x0010: max = 1; break;
                            case 0x0040: max = 2; break;
                            case 0x0060: max = 4; break;
                            case 0x0080: max = 6; break;
                        }
                        if(sn == 0x1410)
                            max = 2;
                        for(var i = 0; i < 6; i++) {
                            setHide("ch"+i, (i >= max));
                        }

                        var nrf = true;
                        switch(sn & 0xff00) {
                            case 0x1000: nrf = true; break;
                            case 0x1100:
                                switch(sn & 0x000f) {
                                    case 0x0004:
                                    case 0x0005: nrf = false; break;
                                    default:     nrf = true; break;
                                }
                                break;
                            case 0x1300: nrf = false; break;
                            case 0x1400: nrf = false; break;
                        }
                        setHide("setcmt", nrf);
                        setHide("setnrf", !nrf);
                        document.getElementsByName("isnrf")[0].value = nrf;
                    })
                });

                modal("{#INV_EDIT_MODAL}: " + obj.name, html);
                ser.dispatchEvent(new Event('change'));

                function ivSave() {
                    var o = {}
                    o.cmd  = "save_iv"
                    o.token = "*"
                    o.id   = obj.id

                    let sn = document.getElementsByName("ser")[0].value
                    if(sn[0] == 'A')
                        sn = convHerf(sn)
                    o.ser  = parseInt(sn, 16)

                    o.name = document.getElementsByName("name")[0].value;
                    o.en   = document.getElementsByName("enable")[0].checked;
                    o.ch = [];
                    for(let i = 0; i < 6; i++) {
                        var q = new Object();
                        q.pwr  = document.getElementsByName("ch_p"+i)[0].value;
                        q.name = document.getElementsByName("ch_n"+i)[0].value;
                        q.yld  = document.getElementsByName("yld_c"+i)[0].value;
                        o.ch.push(q);
                    }
                    if("true" == document.getElementsByName("isnrf")[0].value)
                        o.pa = document.getElementsByName("nrfpa")[0].value;
                    else
                        o.pa   = document.getElementsByName("cmtpa")[0].value;
                    o.freq = document.getElementsByName("freq")[0].value;
                    o.disnightcom = document.getElementsByName("disnightcom")[0].checked;
                    getAjax("/api/setup", cb, "POST", JSON.stringify(o));
                }

                function cmtSearch() {
                    var o = {}
                    o.cmd = "cmt_search"
                    o.token = "*"
                    o.id = obj.id
                    o.to_ch = document.getElementsByName("freq")[0].value;

                    getAjax("/api/ctrl", cb, "POST", JSON.stringify(o));
                }

                function convHerf(sn) {
                    let sn_int = 0n;
                    const CHARS = "0123456789ABCDEFGHJKLMNPRSTUVWXY";

                    for (let i = 0; i < 9; ++i) {
                        const pos = CHARS.indexOf(sn[i])
                        const shift = 42 - 5 * i - (i <= 2 ? 0 : 2)
                        sn_int |= BigInt(pos) << BigInt(shift)
                    }

                    let first4Hex = (sn_int >> 32n) & 0xFFFFn

                    if (first4Hex === 0x2841n)
                        first4Hex = 0x1121n
                    else if (first4Hex === 0x2821n)
                        first4Hex = 0x1141n
                    else if (first4Hex === 0x2801n)
                        first4Hex = 0x1161n

                    sn_int = (sn_int & ~(0xFFFFn << 32n)) | (first4Hex << 32n);

                    return sn_int.toString(16)
                }

                function cb(obj2) {
                    var e = document.getElementById("res");
                    if(!obj2.success)
                        e.innerHTML = "{#ERROR}" + obj2.error;
                    else {
                        modalClose();
                        getAjax("/api/inverter/list", parseIv);
                    }
                }
            }

            function ivDel(obj) {
                var html = ml("div", {class: "row"}, [
                    ml("div", {class: "col-9"}, "{#INV_DELETE_SURE} (" + obj.name + ")"),
                    ml("div", {class: "col-3 a-r"}, ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "{#BTN_YES}", class: "btn", onclick: function() { del(); }}, null)))
                ]);
                modal("{#INV_DELETE_MODAL}: " + obj.name, html);

                function del() {
                    var o = new Object();
                    o.cmd  = "save_iv";
                    o.token = "*"
                    o.id   = obj.id;
                    o.ser  = 0;
                    o.name = "";
                    o.en   = false;
                    o.ch = [];
                    for(let i = 0; i < 6; i++) {
                        var q = new Object();
                        q.pwr  = 0;
                        q.name = "";
                        q.yld  = 0;
                        o.ch.push(q);
                    }
                    getAjax("/api/setup", cb, "POST", JSON.stringify(o));
                }

                function cb(obj) {
                    if(obj.success) {
                        modalClose();
                        getAjax("/api/inverter/list", parseIv);
                    }
                }
            }

            function parseMqtt(obj) {
                for(var i of [["Addr", "broker"], ["Port", "port"], ["ClientId", "clientId"], ["User", "user"], ["Pwd", "pwd"], ["Topic", "topic"], ["Interval", "interval"]])
                    document.getElementsByName("mqtt"+i[0])[0].value = obj[i[1]];
                document.getElementsByName("mqttJson")[0].checked = obj["json"];
                document.getElementsByName("retain")[0].checked = obj.retain
            }

            function parseNtp(obj) {
                for(var i of [["ntpAddr", "addr"], ["ntpPort", "port"], ["ntpIntvl", "interval"]])
                    document.getElementsByName(i[0])[0].value = obj[i[1]];
            }

            function parseSun(obj) {
                document.getElementsByName("sunLat")[0].value = obj["lat"];
                document.getElementsByName("sunLon")[0].value = obj["lon"];
                for(p of [["sunOffsSr", "offsSr"], ["sunOffsSs", "offsSs"]]) {
                    const sel = document.getElementsByName(p[0])[0];
                    for(var i = -60; i <= 60; i++) {
                        sel.appendChild(opt(i, i + " {#NTP_MINUTES}", (i == (obj[p[1]] / 60))));
                    }
                }
            }

            function parsePinout(obj) {
                var e = document.getElementById("pinout");
                /*IF_ESP32*/
                var pinList = esp32pins;
                /*IF_ESP32-S2*/
                pinList = esp32sXpins;
                /*ENDIF_ESP32-S2*/
                /*IF_ESP32-S3*/
                pinList = esp32sXpins;
                /*ENDIF_ESP32-S3*/
                /*IF_ESP32-C3*/
                pinList = esp32c3pins;
                /*ENDIF_ESP32-C3*/
                /*ELSE*/
                var pinList = esp8266pins;
                /*ENDIF_ESP32*/
                pins = [['led0', 'pinLed0', '{#LED_AT_LEAST_ONE_PRODUCING}'], ['led1', 'pinLed1', '{#LED_MQTT_CONNECTED}'], ['led2', 'pinLed2', '{#LED_NIGHT_TIME}']];
                for(p of pins) {
                    e.append(
                        ml("div", {class: "row mb-3"}, [
                            ml("div", {class: "col-12 col-sm-3 my-2"}, p[2]),
                            ml("div", {class: "col-12 col-sm-9"},
                                sel(p[1], pinList, obj[p[0]])
                            )
                        ])
                    );
                }
                e.append(
                    ml("div", { class: "row mb-3" }, [
                        ml("div", { class: "col-12 col-sm-3 my-2" }, "{#LED_POLARITY}"),
                        ml("div", { class: "col-12 col-sm-9" },
                            sel('pinLedHighActive', led_high_active, obj.led_high_active)
                        )
                    ]),
                    ml("div", { class: "row mb-3" }, [
                        ml("div", { class: "col-12 col-sm-3 my-2" }, "{#LED_LUMINANCE} (0-255)"),
                        ml("div", { class: "col-12 col-sm-9" }, ml("input", {class: "text", type: "number", name: "pinLedLum", value: obj.led_lum, min: 0, max: 255}, null))
                    ])
                )
            }

            function parseNrfRadio(obj, objPin) {
                var e = document.getElementById("rf24");
                var en = inp("nrfEnable", null, null, ["cb"], "nrfEnable", "checkbox");
                en.checked = obj["en"];

                /*IF_ESP32*/
                var pinList = esp32pins;
                /*IF_ESP32-S2*/
                pinList = esp32sXpins;
                /*ENDIF_ESP32-S2*/
                /*IF_ESP32-S3*/
                pinList = esp32sXpins;
                /*ENDIF_ESP32-S3*/
                /*IF_ESP32-C3*/
                pinList = esp32c3pins;
                /*ENDIF_ESP32-C3*/
                /*ELSE*/
                var pinList = esp8266pins;
                /*ENDIF_ESP32*/

                e.replaceChildren (
                    ml("div", {class: "row mb-3"}, [
                        ml("div", {class: "col-8 col-sm-3 my-2"}, "{#NRF24_ENABLE}"),
                        ml("div", {class: "col-4 col-sm-9"}, en)
                    ])
                );

                /*IF_ESP32*/
                var pins = [['cs', 'pinCs'], ['ce', 'pinCe'], ['irq', 'pinIrq'], ['sclk', 'pinSclk'], ['mosi', 'pinMosi'], ['miso', 'pinMiso']];
                /*ELSE*/
                var pins = [['cs', 'pinCs'], ['ce', 'pinCe'], ['irq', 'pinIrq']];
                /*ENDIF_ESP32*/
                for(p of pins) {
                    e.append(
                        ml("div", {class: "row mb-3"}, [
                            ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()),
                            ml("div", {class: "col-12 col-sm-9"},
                                sel(p[1], pinList, objPin[p[0]])
                            )
                        ])
                    );
                }
            }

            /*IF_ESP32*/
            function parseCmtRadio(obj) {
                var e = document.getElementById("cmt");
                var en = inp("cmtEnable", null, null, ["cb"], "cmtEnable", "checkbox");
                var pinList = esp32pins;
                /*IF_ESP32-S2*/
                pinList = esp32sXpins;
                /*ENDIF_ESP32-S2*/
                /*IF_ESP32-S3*/
                pinList = esp32sXpins;
                /*ENDIF_ESP32-S3*/
                /*IF_ESP32-C3*/
                pinList = esp32c3pins;
                /*ENDIF_ESP32-C3*/

                en.checked = obj["en"];
                e.replaceChildren (
                    ml("div", {class: "row mb-3"}, [
                        ml("div", {class: "col-8 col-sm-3 my-2"}, "{#CMT_ENABLE}"),
                        ml("div", {class: "col-4 col-sm-9"}, en)
                    ])
                );
                pins = [['sclk', 'pinCmtSclk'], ['sdio', 'pinSdio'], ['csb', 'pinCsb'], ['fcsb', 'pinFcsb'], ['gpio3', 'pinGpio3']];
                for(p of pins) {
                    e.append(
                        ml("div", {class: "row mb-3"}, [
                            ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()),
                            ml("div", {class: "col-12 col-sm-9"},
                                sel(p[1], pinList, obj[p[0]])
                            )
                        ])
                    );
                }

                var i = 0
                while(obj.freq_max >= (obj.freq_min + i * 0.25)) {
                    esp32cmtFreq.push([i, freqFmt.format(obj.freq_min + i * 0.25) + " MHz"])
                    i++
                }
            }
            /*ENDIF_ESP32*/

            /*IF_ETHERNET*/
            function parseEth(obj) {
                var e = document.getElementById("eth");
                var en = inp("ethEn", null, null, ["cb"], "ethEn", "checkbox");
                var pinList = esp32pins;
                /*IF_ESP32-S2*/
                pinList = esp32sXpins;
                /*ENDIF_ESP32-S2*/
                /*IF_ESP32-S3*/
                pinList = esp32sXpins;
                /*ENDIF_ESP32-S3*/
                /*IF_ESP32-C3*/
                pinList = esp32c3pins;
                /*ENDIF_ESP32-C3*/

                en.checked = obj["en"];
                e.replaceChildren (
                    ml("div", {class: "row mb-3"}, [
                        ml("div", {class: "col-8 col-sm-3 my-2"}, "{#ETH_ENABLE}"),
                        ml("div", {class: "col-4 col-sm-9"}, en)
                    ])
                );
                pins = [['cs', 'ethCs'], ['sclk', 'ethSclk'], ['miso', 'ethMiso'], ['mosi', 'ethMosi'], ['irq', 'ethIrq'], ['reset', 'ethRst']];
                for(p of pins) {
                    e.append(
                        ml("div", {class: "row mb-3"}, [
                            ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()),
                            ml("div", {class: "col-12 col-sm-9"},
                                sel(p[1], pinList, obj[p[0]])
                            )
                        ])
                    );
                }
            }
            /*ENDIF_ETHERNET*/

            function parseSerial(obj) {
                var e = document.getElementById("serialCb")
                var l = [["serEn", "show_live_data", "{#LOG_PRINT_INVERTER_DATA}"], ["serDbg", "debug", "{#LOG_SERIAL_DEBUG}"], ["priv", "priv", "{#LOG_PRIVACY_MODE}"], ["wholeTrace", "wholeTrace", "{#LOG_PRINT_TRACES}"], ["log2mqtt", "log2mqtt", "{#LOG_TO_MQTT}"]]
                for(var i of l) {
                    var cb = ml("input", {name: i[0], type: "checkbox"}, null)
                    cb.checked = obj[i[1]]
                    e.appendChild(
                        ml("div", {class: "row mb-3"}, [
                            ml("div", {class: "col-8 col-sm-3"}, i[2]),
                            ml("div", {class: "col-4 col-sm-9"}, cb)
                        ])
                    )
                }
            }

            /*IF_PLUGIN_DISPLAY*/
            function parseDisplay(obj, type, system) {
                /*IF_ESP32*/
                var pinList = esp32pins;
                /*IF_ESP32-S2*/
                pinList = esp32sXpins;
                /*ENDIF_ESP32-S2*/
                /*IF_ESP32-S3*/
                pinList = esp32sXpins;
                /*ENDIF_ESP32-S3*/
                /*IF_ESP32-C3*/
                pinList = esp32c3pins;
                /*ENDIF_ESP32-C3*/
                /*ELSE*/
                var pinList = esp8266pins;
                /*ENDIF_ESP32*/

                for(var i of ["disp_pwr"])
                    document.getElementsByName(i)[0].checked = obj[i];

                var dpins_elem = document.getElementById("dispPins");
                //KEEP this order !!!
                var pins = [['clock', 'disp_clk'], ['data', 'disp_data'], ['cs', 'disp_cs'], ['dc', 'disp_dc'], ['reset', 'disp_rst']];
                /*IF_ESP32*/
                pins.push(['busy', 'disp_bsy']);
                /*ENDIF_ESP32*/
                for(p of pins) {
                    dpins_elem.append(
                        ml("div", {class: "row mb-3", id: "row_" + p[1]}, [
                            ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()),
                            ml("div", {class: "col-12 col-sm-9"},
                                sel(p[1], pinList, obj[p[1]])
                            )
                        ])
                    );
                }
                // keep display types grouped
                var opts = [[0, "{#DISP_NONE}"],
                            [2, "SH1106 128x64 (1.3\")"],
                            [5, "SSD1306 64x48 (0.66\" Wemos OLED Shield)"],
                            [4, "SSD1306 128x32 (0.91\")"],
                            [1, "SSD1306 128x64 (0.96\", 1.54\")"],
                            [6, "SSD1309 128x64 (2.42\")"],
                            [3, "PCD8544 84x48 (1.6\" Nokia 5110)"]];
                /*IF_ESP32*/
                opts.push([10, "ePaper"]);
                /*ENDIF_ESP32*/
                var dtype_sel = sel("disp_typ", opts, obj["disp_typ"]);
                document.getElementById("dispType").append(
                    ml("div", {class: "row mb-3"}, [
                        ml("div", {class: "col-12 col-sm-3 my-2"}, "{#DISP_TYPE}"),
                        ml("div", {class: "col-12 col-sm-9"}, dtype_sel)
                    ])
                );
                opts = [[0, "0&deg;"], [2, "180&deg;"]];
                /*IF_ESP32*/
                    opts.push([1, "90&deg;"]);
                    opts.push([3, "270&deg;"]);
                /*ENDIF_ESP32*/
                document.getElementById("dispRot").append(
                    ml("div", {class: "row mb-3"}, [
                        ml("div", {class: "col-12 col-sm-3 my-2"}, "{#DISP_ROTATION}"),
                        ml("div", {class: "col-12 col-sm-9"}, sel("disp_rot", opts, obj["disp_rot"]))
                    ])
                );

                var opts1 = [[0, "{#DISP_SCREENSAVER_OFF}"], [1, "{#DISP_PIXEL_SHIFT}"], [2, "{#DISP_MOTION_SENS}"]];
                var screensaver_sel = sel("disp_screensaver", opts1, obj["disp_screensaver"]);
                screensaver_sel.id = 'disp_screensaver';
                document.getElementById("screenSaver").append(
                    ml("div", {class: "row mb-3"}, [
                        ml("div", {class: "col-12 col-sm-3 my-2"}, "{#DISP_SCREENSAVER}"),
                        ml("div", {class: "col-12 col-sm-9"}, screensaver_sel)
                    ])
                );

                var esp8266pirpins = [[255, "{#PIN_OFF}"],
                                      [17,  "A0"]];
                document.getElementById("pirPin").append(
                    ml("div", {class: "row mb-3"}, [
                        ml("div", {class: "col-12 col-sm-3 my-2"}, "PIR sensor"),
                        ml("div", {class: "col-12 col-sm-9"}, sel("pir_pin", ("ESP8266" == type) ? esp8266pirpins : pinList, obj["pir_pin"]))
                    ])
                );

                document.getElementsByName("disp_cont")[0].value = obj["disp_cont"];

                dtype_sel.addEventListener('change', function(e) {
                    hideDispPins(pins, parseInt(e.target.value))
                });

                document.getElementById("disp_screensaver").addEventListener('change', function(e) {
                    hideDispPins(pins, parseInt(dtype_sel.value))
                });

                document.getElementsByName("disp_graph_ratio")[0].value = obj["disp_graph_ratio"];

                var opts2 = [[0, "{#GRAPH_LINES_1_2}"], [1, "{#GRAPH_LINES_2_3}"], [2, "{#GRAPH_LINES_1_3}"], [3, "{#GRAPH_LINES_2_4}"], [4, "{#GRAPH_LINES_1_4}"]];
                var graph_size_sel = sel("disp_graph_size", opts2, obj["disp_graph_size"]);
                graph_size_sel.id = 'disp_graph_size';
                document.getElementById("graphSize").append(
                    ml("div", {class: "row mb-3"}, [
                        ml("div", {class: "col-12 col-sm-3 my-2"}, "{#GRAPH_POSITION}"),
                        ml("div", {class: "col-12 col-sm-9"}, graph_size_sel)
                    ])
                );

                hideDispPins(pins, obj.disp_typ);
            }

            function hideDispPins(pins, dispType) {
                // create pin map for each display type.
                // It depends on fix pin array, see var pins: ['clock', 'data', 'cs', 'dc', 'reset', 'busy']
                const pinMap = new Map([
                    [0,  [0,0,0,0,0,0]], //none
                    [1,  [1,1,0,0,0,0]], //SSD1306_128X64
                    [2,  [1,1,0,0,0,0]], //SH1106_128X64
                    [3,  [1,1,1,1,0,0]], //PCD8544_84X48 /nokia5110
                    [4,  [1,1,0,0,0,0]], //SSD1306_128X32
                    [5,  [1,1,0,0,0,0]], //SSD1306_64X48
                    [6,  [1,1,0,0,0,0]], //SSD1309_128x64
                    [10, [1,1,1,1,1,1]]  //ePaper
                ])
                for(var i = 0; i < pins.length; i++) {
                    var cl = document.getElementById("row_" + pins[i][1]).classList;
                    if(pinMap.get(dispType)[i]) {
                        cl.remove("hide");
                    }
                    else {
                        cl.add("hide");
                    }
                }

                const optionsMap = new Map([  // options: [Graph, Luminance, Screensaver]
                    [0,  [0,0,0]], //none
                    [1,  [1,1,1]], //SSD1306_128X64
                    [2,  [1,1,1]], //SH1106_128X64
                    [3,  [1,1,0]], //PCD8544_84X48 /nokia5110
                    [4,  [0,1,1]], //SSD1306_128X32
                    [5,  [0,1,1]], //SSD1306_64X48
                    [6,  [1,1,1]], //SSD1309_128x64
                    [10, [0,0,0]]  //ePaper
                ])

                var screenSaver = document.getElementById("disp_screensaver").value;
                setHide("graphOptions",    !optionsMap.get(dispType)[0]);
                setHide("luminanceOption", !optionsMap.get(dispType)[1]);
                setHide("screenSaver",     !optionsMap.get(dispType)[2]);
                setHide("pirPin",          !(optionsMap.get(dispType)[2] && (screenSaver==2))); // show pir pin only for motion screensaver
            }
            /*ENDIF_PLUGIN_DISPLAY*/

            function tick() {
                document.getElementById("date").innerHTML = toIsoDateStr((new Date((++ts) * 1000)));
            }

            function parse(root) {
                if(null != root) {
                    parseGeneric(root.generic);
                    parseSys(root.system);
                    parseStaticIp(root.static_ip);
                    parseMqtt(root.mqtt);
                    parseNtp(root.ntp);
                    parseSun(root.sun);
                    parsePinout(root.pinout);
                    parseNrfRadio(root.radioNrf, root.pinout);
                    /*IF_ESP32*/
                    parseCmtRadio(root.radioCmt);
                    /*ENDIF_ESP32*/
                    /*IF_ETHERNET*/
                    parseEth(root.eth)
                    /*ENDIF_ETHERNET*/
                    parseSerial(root.serial);
                    /*IF_PLUGIN_DISPLAY*/
                    parseDisplay(root.display, root.system.esp_type, root.system);
                    /*ENDIF_PLUGIN_DISPLAY*/
                    getAjax("/api/inverter/list", parseIv);
                }
            }

            getAjax("/api/setup", parse);
        </script>
    </body>
</html>
